package cn.jimmie.learn.viewArt.weight

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.os.Build
import android.support.annotation.RequiresApi
import android.util.AttributeSet
import android.view.animation.LinearInterpolator
import java.util.*

/**
 * function :
 *
 * <p> Create Time: 2019年01月20日 13:25 </p>
 * <p> @author Jimmie.Qian  </p>
 */
class ButterflyAnimatorView(context: Context, attrs: AttributeSet) : ButterflyView(context, attrs) {

    private val mRandom = Random()
    private var mMoveDegree = 0f
    private var orientation = TOP
    private var mOrientationAnimator = ValueAnimator.ofFloat()
    private var mDistance = 0f
    var mMoveSpeed = 3_000f / h
        set(value) {
            field = 3_000f / h / value
        }

    private val mDeathAnimator = ValueAnimator.ofInt(15)

    // 蝴蝶的位置
    private var mX: Float
    private var mY: Float
    // 食物的位置
    private var mFoodX = 0f
    private var mFoodY = 0f

    private var isDeath = false
    private var mLastDeathValue = 0

    @Volatile
    private var mButterflyShown = true

    var mListener: OnEventListener? = null

    fun reset() {
        mOrientationAnimator.cancel()
        mDeathAnimator.cancel()
        changeOrientation(TOP)
        isDeath = false
        mButterflyShown = true
        mX = w / 2f
        mY = h / 2f
        createFoodXY()
    }

    fun go(o: Int) {
        isDeath && return

        val duration = changeOrientation(o)
        mOrientationAnimator.setFloatValues(mDistance)
        mOrientationAnimator.duration = duration.toLong()
        mOrientationAnimator.cancel()
        mOrientationAnimator.start()
    }

    interface OnEventListener {
        fun onHitWall()
        fun onHitFood()
    }

    init {
        mX = w / 2f
        mY = h / 2f
        createFoodXY()

        mOrientationAnimator.interpolator = LinearInterpolator()
        mOrientationAnimator.addUpdateListener {
            val value = it.animatedValue as Float
            if (value > mDistance - h / 20f) return@addUpdateListener

            when (orientation) {
                LEFT -> {
                    mX = mDistance - value
                }
                RIGHT -> {
                    mX = w - mDistance + value
                }
                TOP -> {
                    mY = mDistance - value
                }
                BOTTOM -> {
                    mY = h - mDistance + value
                }
            }
            invalidate()
        }

        mDeathAnimator.interpolator = LinearInterpolator()
        mDeathAnimator.duration = 2_000
        mDeathAnimator.addUpdateListener {
            val value = it.animatedValue as Int
            if (mLastDeathValue != value) {
                mLastDeathValue = value
                mButterflyShown = !mButterflyShown
                invalidate()
            }
        }
        mDeathAnimator.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                mListener?.onHitWall()
            }
        })
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onDraw(canvas: Canvas) {
        !mButterflyShown && return

        if (checkHitFood()) {
            mListener?.onHitFood()
            createFoodXY()
        }
        if (checkHitWall()) {
            isDeath = true
            mDeathAnimator.cancel()
            mDeathAnimator.start()
        }
        // 画食物
        paint.strokeWidth = 10 * dp
        paint.color = Color.RED
        canvas.drawPoint(mFoodX, mFoodY, paint)

        canvas.save()
        canvas.translate(mX - w / 2, mY - h / 2)
        canvas.rotate(mMoveDegree, w / 2f, h / 2f)
        canvas.scale(0.2f, 0.2f, w / 2f, h / 2f)
        super.onDraw(canvas)
        canvas.restore()
    }

    override fun onDetachedFromWindow() {
        mListener = null
        mDeathAnimator.cancel()
        mDeathAnimator.removeAllUpdateListeners()
        mDeathAnimator.removeAllListeners()

        mOrientationAnimator.cancel()
        mOrientationAnimator.removeAllUpdateListeners()
        super.onDetachedFromWindow()
    }

    private fun changeOrientation(o: Int): Float {
        orientation = o
        return when (o) {
            LEFT -> {
                mMoveDegree = 270f
                mDistance = mX
                mDistance * mMoveSpeed
            }
            RIGHT -> {
                mMoveDegree = 90f
                mDistance = w - mX
                mDistance * mMoveSpeed
            }
            TOP -> {
                mMoveDegree = 0f
                mDistance = mY
                mDistance * mMoveSpeed
            }
            else -> {
                mMoveDegree = 180f
                mDistance = h - mY
                mDistance * mMoveSpeed
            }
        }
    }

    private fun createFoodXY() {
        mFoodX = mRandom.nextInt((w - w / 10f).toInt()).toFloat() + w / 20f
        mFoodY = mRandom.nextInt((h - h / 10f).toInt()).toFloat() + h / 20f
    }

    private fun checkHitFood(): Boolean {
        return (Math.abs(mFoodX - mX) < 0.06f * w && Math.abs(mFoodY - mY) < 0.06f * h)
    }

    private fun checkHitWall(): Boolean {
        if (isDeath) return false
        return mX < h / 20 + 10 || mX > h * 19 / 20 - 10 || mY < h / 20 + 10 || mY > h * 19 / 20 - 10
    }

    companion object {
        const val LEFT = 1
        const val RIGHT = 2
        const val TOP = 3
        const val BOTTOM = 4
    }
}